﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Problem010
{
    static class Program
    {
        private const int MaxPrimeNumber = 2000000;

        static void Main()
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var range = Enumerable.Range(2, 1).Union(Enumerable.Range(1, (Int32.MaxValue-1)/2).Select(x => 2 * x + 1));
            Console.WriteLine(GeneratePrimes(range).TakeWhile(n => n < MaxPrimeNumber).Sum());
            stopwatch.Stop();

            Console.WriteLine("Execution time: {0}ms", stopwatch.ElapsedMilliseconds);

            Console.ReadKey();
        }

        private static IEnumerable<long> GeneratePrimes(IEnumerable<int> range)
        {
            var primes = from number in range
                         where number.IsPrime()
                         select (long)number;

            return primes;
        }

        private static readonly List<long> knownPrimes = new List<long>();

        private static bool IsPrime(this int number)
        {
            // To check for a prime number, check if the number is 
            // divisible by all prime numbers less than equal to its square root.
            // Hence, knownPrimes.TakeWhile(n => n*n <= number)
            var isPrime = knownPrimes.TakeWhile(n => n*n <= number).TrueForAll(x => 0 != (number % x));

            if (isPrime)
                knownPrimes.Add(number);

            return isPrime;
        }

        private static bool TrueForAll<T>(this IEnumerable<T> sequence, Predicate<T> test)
        {
            foreach (var t in sequence)
            {
                if (!test(t))
                    return false;
            }

            return true;
        }
    }
}
